home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 265_01 / cugcpio.c < prev    next >
Text File  |  1990-02-13  |  12KB  |  489 lines

  1. /*
  2.  *    c u g c p i o . c
  3.  *    -----------------
  4.  *    The CUG Data Exchange Format Archive Creator/Extractor.
  5.  *
  6.  *    Written by    Rainer Gerhards
  7.  *            Petronellastr. 6
  8.  *            D-5112 Baesweiler
  9.  *            West Germany
  10.  *
  11.  *            Phone (West Germany) 2401 - 1601
  12.  *
  13.  *    release history
  14.  *    ---------------
  15.  *    Mar 26, 1988    begin implementation
  16.  *    Nov 16, 1988    switches d and p added
  17.  */
  18. #include "environ.h"
  19. #include <stdio.h>
  20. #include <ctype.h>
  21.  
  22.  
  23. /*
  24.  *    preprocessor constants
  25.  *    ----------------------
  26.  */
  27. #define    VERSION        2        /* current program version    */
  28. #define    MAGIC        070707        /* magic archive number        */
  29. #define    TRAILER        "TRAILER!!!"    /* trailer file name        */
  30. #define    MAKEFILE    "makefile"    /* name of makefiles        */
  31. #define    FILLCHR        '\032'        /* block fill character        */
  32. #define    MAXNMSZ        100        /* longest possible file name    */
  33. #define    BUFSIZE        512        /* C-library max buffer size    */
  34. #define    TABCOLS        8        /* OS tab settings        */
  35. #define    BLOCKSZ        512        /* output block size        */
  36.  
  37. /*
  38.  * The following defines describe the processing modes. They are
  39.  * mainly used to avoid enums.
  40.  */
  41. #define    CREATE        0
  42. #define    EXTRACT        1
  43. #define    CATALOG        2
  44.  
  45. /*
  46.  *    static data
  47.  *    -----------
  48.  */
  49. STATIC FILE    *archive;        /* archive file pointer        */
  50. STATIC char    opn_mode[8];        /* archive file open mode    */
  51. STATIC int    procmode = CATALOG;    /* processing mode        */
  52. STATIC int    verbose = FALSE;    /* verbose output        */
  53. STATIC int    silent = FALSE;        /* totally silent mode        */
  54. STATIC int    exptab = FALSE;        /* expand tabulation stops    */
  55. STATIC int    convert = FALSE;    /* do several conversions    */
  56. STATIC int    makeflok = FALSE;    /* look for makefiles        */
  57. STATIC int    ignpath = FALSE;    /* ignore path names in archive */
  58. STATIC int    destroy = FALSE;    /* destroy existing files    */
  59.  
  60. /*
  61.  *    functions
  62.  *    ---------
  63.  */
  64.  
  65.  
  66. /*---------------------------------------------------------------------------
  67.  * Display usage information. This function terminates the program!
  68.  */
  69. void        usage()
  70. {
  71. fprintf(stderr, "Usage:\tcugcpio -[i|o|t][cdempsv] archive [files...]\n");
  72. fprintf(stderr, "\nprocessing modes:\n");
  73. fprintf(stderr, "i\textract files\n");
  74. fprintf(stderr, "o\tcreate archive\n");
  75. fprintf(stderr, "t\tlist archive directory\n");
  76. fprintf(stderr, "\nprocessing modifiers (options):\n");
  77. fprintf(stderr, "c\tdo several conversions\n");
  78. fprintf(stderr, "d\tsilently overwrite existing files on extract\n");
  79. fprintf(stderr, "e\texpand horizontal tabs (input only)\n");
  80. fprintf(stderr, "m\tdon't expand HTs in makefiles\n");
  81. fprintf(stderr, "p\tignore stored path name\n");
  82. fprintf(stderr, "s\tsilent operation - no messages displayed\n");
  83. fprintf(stderr, "v\tverbose listing\n");
  84. exit(2);
  85. /*NOTREACHED*/
  86. }
  87.  
  88.  
  89. /*---------------------------------------------------------------------------
  90.  * Check if file is existent. We assume it isn't, if we can't open it.
  91.  * This may not be the safest method, but it should be the most portable one.
  92.  */
  93. int        exist(file)
  94. char        *file;
  95. {
  96. FILE        *fp;
  97. int        ret;
  98.  
  99. ret = ((fp = fopen(file, OPM_RT)) == NULL) ? 0 : 1;
  100. if(ret)
  101.     fclose(fp);
  102. return(ret);
  103. }
  104.  
  105.  
  106. /*---------------------------------------------------------------------------
  107.  * Test if character is pathname-delimiter. Returns 1 if yes, 0 otherwise.
  108.  */
  109. STATIC int    pathdelm(c)
  110. int        c;
  111. {
  112. int        state;
  113.  
  114. if((c == '/') || (c == '\\'))
  115.     state = 1;    /* delemiter found!    */
  116. else
  117.     state = 0;
  118. return(state);
  119. }
  120.  
  121.  
  122. /*---------------------------------------------------------------------------
  123.  * Get filename only (path stripped).
  124.  */
  125. STATIC char    *nameonly(cp)
  126. register char    *cp;
  127. {
  128. register char    *orgcp;
  129.  
  130. for(orgcp = cp ; *cp ; ++cp)
  131.     ;        /* search end of string        */
  132. for( ; !pathdelm(*cp) && (cp != orgcp) ; --cp)
  133.     ;        /* search path delemiter    */
  134. if(pathdelm(*cp))
  135.     ++cp;
  136. return(cp);
  137. }
  138.  
  139.  
  140. /*---------------------------------------------------------------------------
  141.  * Get pathname only (filename stripped).
  142.  */
  143. STATIC char    *pathonly(cp)
  144. char        *cp;
  145. {
  146. register int    i;
  147. register char    *endcp;
  148. static char    pathname[MAXNMSZ];
  149.  
  150. endcp = nameonly(cp);
  151. for(i = 0 ; cp != endcp ; ++cp, ++i)
  152.     pathname[i] = *cp;
  153. pathname[i] = '\0';
  154. return(pathname);
  155. }
  156.  
  157.  
  158. /*---------------------------------------------------------------------------
  159.  * Convert String to lower case.
  160.  */
  161. STATIC void    lowerstr(cp)
  162. register char    *cp;
  163. {
  164. for( ; *cp ; ++cp)
  165.     if(isupper(*cp))
  166.         *cp = tolower(*cp);
  167. }
  168.  
  169.  
  170. /*---------------------------------------------------------------------------
  171.  * Set operation modes according to switch characters. If an error is
  172.  * detected in them the usage message is displayed and the program terminates.
  173.  */
  174. STATIC void    setmodes(sw)
  175. register char    *sw;
  176. {
  177. while(*sw)
  178.     switch(*sw++)
  179.         {
  180.         case 'o':    procmode = CREATE;    /* output    */
  181.                 strcpy(opn_mode, OPM_WB);
  182.                 break;
  183.         case 'i':    procmode = EXTRACT;    /* input    */
  184.                 strcpy(opn_mode, OPM_RB);
  185.                 break;
  186.         case 't':    procmode = CATALOG;    /* catalog    */
  187.                 strcpy(opn_mode, OPM_RB);
  188.                 break;
  189.         case 'v':    verbose = TRUE;        /* verbose     */
  190.                 break;
  191.         case 's':    silent = TRUE;        /* total silent    */
  192.                 break;
  193.         case 'c':    convert = TRUE;        /* conversion    */
  194.                 break;
  195.         case 'e':    exptab = TRUE;        /* expand HT    */
  196.                 break;
  197.         case 'm':    makeflok = TRUE;    /* makefile opt    */
  198.                 break;
  199.         case 'p':    ignpath = TRUE;        /* ignore path    */
  200.                 break;
  201.         case 'd':    destroy = TRUE;        /* destroy files*/
  202.                 break;
  203.         default:    usage();
  204.                 /*NOTREACHED*/
  205.         }
  206. }
  207.  
  208.  
  209. /*---------------------------------------------------------------------------
  210.  * Write archive file header
  211.  */
  212. void        wrthead(name, textsize)
  213. register char    *name;
  214. long        textsize;
  215. {
  216. fprintf(archive,
  217.        "%6.6o%6.6o%6.6o%6.6o%6.6o%6.6o%6.6o%6.6o%11.11lo%6.6o%11.11lo",
  218.        MAGIC, 0, 0, 0100666, 0, 0, 1, 0, 0l, strlen(name) + 1, textsize);
  219. for( ; *name ; ++name)
  220.     fputc(((convert == TRUE) && islower(*name)) ? toupper(*name) : *name,
  221.            archive);
  222. fputc('\0', archive);
  223. }
  224.  
  225.  
  226. /*---------------------------------------------------------------------------
  227.  * Read archive file header. Returns TRUE if read head was trailer record
  228.  * otherwise FALSE. If the magic number is incorrect, an error message is
  229.  * generated and the program terminated.
  230.  */
  231. STATIC int    get_head(name, textsize)
  232. char        *name;
  233. long        *textsize;
  234. {
  235. register char    *cp;
  236. int        magic;
  237. int        namesize;
  238. int        retval;
  239.  
  240. fscanf(archive, "%6o%*6o%*6o%*6o%*6o%*6o%*6o%*6o%*11lo%6o%11lo",
  241.       &magic, &namesize, textsize);
  242. if(magic == 070707)
  243.     {
  244.     cp = name;
  245.     while(namesize--)
  246.         *cp++ = fgetc(archive);
  247.     *cp = '\0';
  248.     }
  249. else
  250.     {
  251.     fprintf(stderr, "ERROR: Archive file inconsistency, magic = %6.6o\n");
  252.     exit(1);
  253.     }
  254. retval = ((*textsize == 0l) && (!strcmp(name, TRAILER))) ? TRUE : FALSE;
  255. if(convert == TRUE)
  256.     lowerstr(name);
  257. return(retval);
  258. }
  259.  
  260.  
  261. /*---------------------------------------------------------------------------
  262.  * Skip n bytes of the input archive file.
  263.  */
  264. STATIC void    skipinp(n)
  265. long        n;
  266. {
  267. fseek(archive, n, 1);
  268. }
  269.  
  270.  
  271. /*---------------------------------------------------------------------------
  272.  * Write single file to archive.
  273.  */
  274. void        wrtout(fil)
  275. char        *fil;
  276. {
  277. register FILE    *fp;
  278. register int    c;
  279. int        i;
  280. int        curcol = 0;
  281. long        headpos;
  282. long        textsize = 0l;
  283. long        nonascii = 0l;
  284. long        nonprint = 0l;
  285.  
  286. if((fp = fopen(fil, "r")) == NULL)
  287.     fprintf(stderr, "ERROR: Can't open %s\n", fil);
  288. else
  289.     {
  290.     headpos = ftell(archive);
  291.     /* The following written dummy header becomes updated at end of
  292.        processing. The actual file size isn't known at this moment. */
  293.     wrthead(fil, 0l);
  294.     /* copy file */
  295.     while((c = fgetc(fp)) != EOF)
  296.         {
  297.         if((c == '\t') && (exptab == TRUE))
  298.             {
  299.             i = TABCOLS - (curcol % TABCOLS);
  300.             textsize = textsize + i;
  301.             curcol += i;
  302.             while(i--)
  303.                 fputc(' ', archive);
  304.             }
  305.         else
  306.             {
  307.             if(c == '\n')
  308.                 curcol = 0;
  309.             else
  310.                 ++curcol;
  311.             if(!isascii(c))
  312.                 ++nonascii;
  313.             else if(!isprint(c) && (c != '\n'))
  314.                 ++nonprint;
  315.             fputc(c, archive);
  316.             ++textsize;
  317.             }
  318.         }
  319.     /* copy done, update header */
  320.     fseek(archive, headpos, 0);    /* go back to update header    */
  321.     wrthead(fil, textsize);
  322.     fseek(archive, 0l, 2);        /* back